

from wsgiref import headers
class Locale(object):
    def __init__(self, language, country):
        self.language = language;
        self.country = country;
    
    def equals(self,obj):
        if (isinstance(obj, Locale)):
            return True;
        else:
            return False;

    def getLanguage(self):
        return self.language;

    def getCountry(self):
        return self.country;
    
class FileException (Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)
    
class CacheException (Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class Cache:
    def get(self, key, expiration = False):
        from lib import Util;
        Util.abstract();
    def set(self, key, value):
        from lib import Util;
        Util.abstract();
    def delete(self, key):
        from lib import Util;
        Util.abstract();

from google.appengine.ext import db
class File(db.Model):
	id = db.StringProperty();
	datakey = db.StringProperty(multiline=False);
	content = db.BlobProperty();
	created_on = db.DateTimeProperty(auto_now_add=True);
	modified_on = db.DateTimeProperty(auto_now_add=True);
	accessed_on = db.DateTimeProperty(auto_now_add=True);
	tmp = db.BooleanProperty(required=False, default=False)

	@classmethod
	def doesExists(self, datakey):
		# dont save directory name as filename is unique
		q = File.all();
		q.filter('datakey = ', datakey);
		results = q.fetch(1);		

		if len(results) > 0:
			return True;
		else:
			return False;

	
	@classmethod
	def get(self, datakey, createIfMissing = True):
		return self.getAll(datakey, createIfMissing).content;

	@classmethod
	def getAll(self, key, createIfMissing = True):
		q = File.all();
		q.filter('datakey = ', key);

		results = q.fetch(1);		

		data = None;
		
		if len(results) == 1:
			data = results[0];

		if (data == None and createIfMissing == True):
			data = File(datakey = key);
			data.put();

		return data;




class CacheFile(Cache):
    def get(self, key, expiration = False):
	from lib import Config;
	if(not Config.get('cache_objects')):
		return False;
        
        fileHandler = File();
	
        if (not fileHandler.doesExists(key)):
	    return False;

	fileData = fileHandler.getAll(key);

	import time;
	
	now = time.time();
	
	mtime = fileData.accessed_on;
	
	mtime = str(mtime);
	mtime = mtime[0:mtime.rfind('.')];
	mtime = time.mktime(time.strptime(mtime, '%Y-%m-%d %H:%M:%S'))
	
	if (not expiration):
            # if no expiration time was given, fall back on the global config
	    from lib import Config;
            expiration = Config.get('cache_time');
	


	if ((mtime != False) and (now - mtime) < expiration):
		#[TODO]
		pass;
		#return False;

	data = fileData.content;
        
	#update accesstime

	import datetime;

	fileData.accessed_on = fileData.accessed_on.today()
	fileData.put();

        return data;


    def set(self, key, value, temp = False):
	from lib import Config;
	if(not Config.get('cache_objects')):
		return False;
        
        
	# we serialize the whole request object, since we don't only want the
	# responseContent but also the postBody used, headers, size, etc
        
        data = value;
	#p.serialize(value);

	fileData = File().getAll(key, True);

	fileData.content = data;

	fileData.accessed_on = fileData.accessed_on.now();
	
	fileData.put();

    def delete(self, key):
	from lib import Config;
	if(not Config.get('cache_objects')):
		return False;
        
	fileData = File().getAll(key);
	fileData.delete();

        

class RemoteContentException (Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)
    
class RemoteContent:
    def fetch(self, request, context):
        from lib import Util;
        Util.abstract();

class RemoteContentFetcher():
    fetcher = None;
    def setNextFetcher(self,fetcher = None):
        self.fetcher = fetcher;
    
    def fetchRequest(self,request):
        from lib import Util;
        Util.abstract();
        
    def getNextFetcher(self):
        self.fetcher;

#
# Bag of options for making a request.
#
# This object is mutable to keep us sane. Don't mess with it once you've
# sent it to RemoteContentRequest or bad things might happen.
#
class Options():

    def __init__(self):
	    self.ignoreCache = False;
	    self.ownerSigned = True;
	    self.viewerSigned = True;

    #
    # Copy constructor
    #
    def copyOptions(self, copyFrom):

        self.ignoreCache = copyFrom.ignoreCache;
        self.ownerSigned = copyFrom.ownerSigned;
        self.viewerSigned = copyFrom.viewerSigned;


class RemoteContentRequest():
    # these are used for making the request
    SC_OK = 200; #Please, use only for testing!
    DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded; charset=utf-8";

    def __init__(self,uri, headers = {}, postBody = None):
        self.uri = uri;
        self.headers = headers;
        self.postBody = postBody;
	import time;
        self.created = time.time();
        self.__method = '';
        # these fields are filled in once the request has completed
        self.__responseContent = False;
        self.__responseSize = False;
        self.__responseHeaders = False;
        self.__httpCode = False;
        self.__contentType = None;
        self.__options = '';
        self.handle = False;

    def createRemoteContentRequest(self, method, uri, headers, postBody, options):
        self.__method = method;
        self.uri = uri;
        self.options = options;
        # Copy the headers
        from lib import Util
        if (not Util.is_set(headers)):
            self.headers = '';
        else:
            setPragmaHeader = False;
            tmpHeaders = '';
            for key, value in enumerate(headers):
                # Proxies should be bypassed with the Pragma: no-cache check.
                if (key == "Pragma" and options.ignoreCache):
                    value = "no-cache";
                    setPragmaHeader = True;
                tmpHeaders = tmpHeaders + key + ":" + value + "\n";
            # Bypass caching in proxies as well.
            if (not setPragmaHeader and options.ignoreCache):
                tmpHeaders = tmpHeaders + "Pragma:no-cache\n";
            self.headers = tmpHeaders;
        if (postBody == None):
            self.postBody = None;
        else:
            self.postBody = Util.array_merge(postBody, self.postBody);

	type = self.getHeader("Content-Type");
        if (not Util.is_set(type)):
            self.__contentType = RemoteContentRequest.DEFAULT_CONTENT_TYPE;
        else:
            self.__contentType = type;

    #
    # Creates a new request to a different URL using all request data from
    # an existing request.
    #
    # @param uri
    # @param base The base request to copy data from.
    #
    @staticmethod
    def createRemoteContentRequestWithUriBase(self, uri, base):
        self.uri = uri;
        self.__method = base.method;
        self.options = base.options;
        self.headers = base.headers;
        self.__contentType = base.contentType;
        self.postBody = base.postBody;

    #
    # Basic GET request.
    #
    # @param uri
    #
    def createRemoteContentRequestWithUri(self, uri):
        self.createRemoteContentRequest(self, "GET", uri, None, None, RemoteContentRequest.getDefaultOptions());

    #
    # GET with options
    #
    # @param uri
    # @param options
    #
    def createRemoteContentRequestWithUriOptions(self, uri, options):
        self.createRemoteContentRequest(self, "GET", uri, None, None, options);

    #
    # GET request with custom headers and default options
    # @param uri
    # @param headers
    #
    def RemoteContentRequestWithUriHeaders(self, uri, headers):
        self.createRemoteContentRequest(self,"GET", uri, headers, None, RemoteContentRequest.getDefaultOptions());

    #
    # GET request with custom headers + options
    # @param uri
    # @param headers
    # @param options
    #
    def createRemoteContentRequestWithUriHeadersOptions(self, uri, headers, options):
        self.createRemoteContentRequest(self, "GET", uri, headers, None, options);

    #
    # Basic POST request
    # @param uri
    # @param postBody
    #
    def RemoteContentRequestWithUriPostBody(self, uri, postBody):
        self.createRemoteContentRequest(self,"POST", uri, None, postBody, RemoteContentRequest.getDefaultOptions());

    #
    # POST request with options
    # @param uri
    # @param postBody
    # @param options
    #
    def createRemoteContentRequestWithUriPostBodyOptions(self, uri, postBody, options):
        self.createRemoteContentRequest(self, "POST", uri, None, postBody, options);

    #
    # POST request with headers
    # @param uri
    # @param headers
    # @param postBody
    #
    def createRemoteContentRequestWithUriHeadersPostBody(self, uri, headers, postBody):
        self.createRemoteContentRequest(self, "POST", uri, headers, postBody, RemoteContentRequest.getDefaultOptions());

    #
    # POST request with options + headers
    # @param uri
    # @param headers
    # @param postBody
    # @param options
    #
    def createRemoteContentRequestWithUriHeadersPostBodyOptions(self, uri, headers, postBody, options):
        self.createRemoteContentRequest(self,"POST", uri, headers, postBody, options);

    #
    # Creates a simple GET request
    #
    # @param uri
    # @param ignoreCache
    #
    def getRequest(self, uri, ignoreCache):
        
        options = Options();
        options.ignoreCache = ignoreCache;
        return self.createRemoteContentRequestWithUriOptions(self, uri, options);

    #
    # Simple constructor for setting a basic response from a string. Mostly used
    # for testing.
    #
    # @param body
    #
    def getHttpFalseResponseBody(self, body):
        return self.createFalseResponse(self, RemoteContentRequest.SC_OK, body, None);

    def __createFalseResponse_(self, httpCode, body, headers):
        self.__httpCode = httpCode;
        self.__responseContent = body;
        self.headers = headers;
        return self;

    # returns a hash code which identifies this request, used for caching
    # takes url and postbody into account for constructing the sha1 checksum
    def toHash(self):
	import md5
	
        return md5.new(self.uri + self.postBody).hexdigest();

    @staticmethod
    def getDefaultOptions():

        return Options();


    def getContentType(self):

        return self.__contentType;


    def getHttpCode(self):

        return self.__httpCode;


    def getResponseContent(self):

        return self.__responseContent;


    def getResponseHeaders(self):

        return self.__responseHeaders;


    def getResponseSize(self):

        return self.__responseSize;


    def getHeaders(self):

        return self.headers;


    def isPost(self):

        return (self.postBody != None);


    def hasHeaders(self):

        return (len(self.headers) > 0);


    def getPostBody(self):

        return self.postBody;


    def getUrl(self):

        return self.uri;


    def getMethod(self):

        return self.__method;


    def getOptions(self):

        if (len(self.options) == 0):
            import Options;
            return Options();
    
        return self.options;


    def setContentType(self, type):

        self.__contentType = type;


    def setHttpCode(self, code):

        self.__httpCode = int(code);


    def setResponseContent(self, content):

        self.__responseContent = content;


    def setResponseHeaders(self, headers):

        self.__responseHeaders = headers;


    def setResponseSize(self, size):

        self.__responseSize = int(size);


    def setHeaders(self, headers):

        self.headers = headers;


    #FIXME: Find a better way to do this
    # The headers can be an array of elements.
    def getHeader(self, headerName):

        headers = self.headers.split("\n");
        for header in headers:
            key = header.split(":", 2);
            if (key[0] == headerName):
                return key[1].strip();
    
        return None;


    #FIXME: Find a better way to do this
    # The headers can be an array of elements.
    def getResponseHeader(self, headerName):
        #headers = self.responseHeaders.split(":");
	headers = self.__responseHeaders;
        for header in headers:
            if (header == headerName):
                return headers[header].strip();
        
    
        return None;


    def getCreated(self):

        return self.created;


    def setPostBody(self, postBody):

        self.postBody = postBody;


    def setUri(self, uri):

        self.uri = uri;


class HttpServlet:

	 # 
	 #  Enables output buffering so we can do correct Util.header handling in the destructor
	 # 
	def __init__(self):
		self.__lastModified_ = False;
		self.__contentType_ = 'text/html';
		self.__charset_ = 'UTF-8';
		self.__noCache_ = False;
		self.noHeaders = False;
		
		from lib import Config;
		#  set our default cache time (config cache time defaults to 24 hours aka 1 day)
		self.__cacheTime_ = Config.get('cache_time');
		#  to do our Util.header magic, we need output buffering on
		#ob_start(); [TODO need to implement]

	def getCharset(self):
		return self.__charset_;
	

	def setCharset(self, charset):
		self.__charset_ = charset;

	 # 
	 #  Sets the time in seconds that the browser's cache should be 
	 #  considered out of date (through the Expires Util.header) 
	 # 
	 #  @param int time time in seconds
	 # 
	def setCacheTime(self, times):
		self.__cacheTime_ = times;
	

	 # 
	 #  Returns the time in seconds that the browser is allowed to cache the content
	 # 
	 #  @return int time
	 # 
	def getCacheTime(self):
		return self.__cacheTime_;
	

	 # 
	 #  Sets the content type of this request (forinstance: text/html or text/javascript, etc) 
	 # 
	 #  @param string type content type Util.header to use
	 # 
	def setContentType(self, types):
		self.__contentType_ = types;
	

	 # 
	 #  Returns the current content type 
	 # 
	 #  @return string content type string
	 # 
	def getContentType(self):
		return self.__contentType_;
	

	 # 
	 #  returns the current last modified time stamp
	 # 
	 #  @return int timestamp
	 # 
	def getLastModified(self):
		return self.__lastModified_;

	 # 
	 #  Sets the last modified timestamp. It automaticly checks if this timestamp
	 #  is larger then its current timestamp, and if not ignores the call
	 # 
	 #  @param int modified timestamp
	 # /
	def setLastModified(self, modified):
		self.__lastModified_ = max(self.__lastModified_, modified);
	

	 # 
	 #  Sets the noCache boolean. If its set to True, no-caching Util.headers will be send
	 #  (pragma no cache, expiration in the past)
	 # 
	 #  @param boolean cache send no-cache Util.headers?
	 # 
	def setNoCache(self, cache = False):
		self.__noCache_ = cache;

	 # 
	 #  returns the noCache boolean
	 # 
	 #  @return boolean
	 # 
	def getNoCache(self):
		return self.__noCache_;

	 # 
	 #  Code ran after the event handler, adds Util.headers etc to the request
	 #  If noUtil.headers is False, it adds all the correct http/1.1 Util.headers to the request
	 #  and deals with modified/expires/e-tags/etc. This makes the server behave more like
	 #  a real http server.
	 # 
	def __del__(self):
		
		from lib import Util;
		if (self.noHeaders):
			return;

		Util.header("Content-Type: " + self.__contentType_ + ";" + (" charset=" + self.__charset_ if (len(self.__charset_) > 0) else ''));
		Util.header('Accept-Ranges: bytes');
		#content = ob_get_contents();

		if (self.__noCache_):
			Util.header("Cache-Control: no-cache, must-revalidate");
			Util.header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
			return;

	
		#  attempt at some propper Util.header handling from php
		#  this departs a little from the app code but it should give is valid http protocol handling
		Util.header('Cache-Control: public,max-age=' + self.__cacheTime_);
		#[TODO]
		
		import time;
		cacheTime = time.strftime('%a, %d %m %Y %H:%M:%S', time.localtime(time.time() + self.__cacheTime_));
		Util.header("Expires: " + cacheTime + " GMT");
		#  Obey browsers (or proxy's) request to send a fresh copy if we recieve a no-cache pragma or cache-control request
		#if (! isset(_SERVER['HTTP_PRAGMA']) || ! strstr(strtolower(_SERVER['HTTP_PRAGMA']), 'no-cache') && (! isset(_SERVER['HTTP_CACHE_CONTROL']) || ! strstr(strtolower(_SERVER['HTTP_CACHE_CONTROL']), 'no-cache'))) 
		#if (True):
		from lib import RequestUtil;
		requestUtilHandler = RequestUtil.getInstance();

		if (not requestUtilHandler.SERVER.has_key('HTTP_PRAGMA') or (requestUtilHandler.SERVER['HTTP_PRAGMA'].lower().find('no-cache') == -1) and (not requestUtilHandler.SERVER.has_key('HTTP_CACHE_CONTROL') or requestUtilHandler.SERVER['HTTP_CACHE_CONTROL'].lower().find('no-cache') == -1)):
			#  If the browser send us a E-TAG check if it matches (md5 sum of content), if so send a not modified Util.header instead of content
			import md5
			etag = '"' + md5.new(content).hexdigest() + '"';
			#if (isset(_SERVER['HTTP_IF_NONE_MATCH']) && _SERVER['HTTP_IF_NONE_MATCH'] == etag) 
			#if(True):
			if (requestUtilHandler.SERVER.has_key('HTTP_IF_NONE_MATCH') and requestUtilHandler.headers['HTTP_IF_NONE_MATCH'] == etag) :
				Util.header("ETag: \"" + etag + "\"");
				if (self.__lastModified_):
					cacheTime = time.strftime('%a, %d %m %Y %H:%M:%S', self.__lastModified_);
					Util.header('Last-Modified: ' + cacheTime + ' GMT');
				
				Util.header("HTTP/1.1 304 Not Modified");
				#Util.header('Content-Length: 0', True); # not allowed
				Util.ob_end_clean();
				Util.die();
			
			Util.header("ETag: " + etag);
			#  If no etag is present, then check if maybe this browser supports if_modified_since tags,
			#  check it against our lastModified (if it's set)
			#if (isset(_SERVER['HTTP_IF_MODIFIED_SINCE']) && self.lastModified && ! isset(_SERVER['HTTP_IF_NONE_MATCH'])) 
			#if (True):
			if (requestUtilHandler.SERVER.has_key('HTTP_IF_MODIFIED_SINCE') and self.__lastModified_ and not requestUtilHandler.SERVER.has_key('HTTP_IF_NONE_MATCH')):
				if_modified_since = strtotime(requestUtilHandler.SERVER['HTTP_IF_MODIFIED_SINCE']);
				if (self.__lastModified_ <= if_modified_since):
					cacheTime = time.strftime('%a, %d %m %Y %H:%M:%S', self.__lastModified_);
					Util.header('Last-Modified: ' + cacheTime + ' GMT');
					Util.header("HTTP/1.1 304 Not Modified");
					#Util.header('Content-Length: 0', True); # not allowed
					Util.ob_end_clean();
					Util.die();
			
			cacheTime = time.strftime('%a, %d %m %Y %H:%M:%S', (self.__lastModified_ if (self.__lastModified_) else time.time()));

			Util.header('Last-Modified: ' + gmdate('D, d M Y H:i:s', cacheTime) + ' GMT', True);



import types, string

class SecurityTokenDecoder:

	 # Decrypts and verifies a gadget security token to return a gadget token.
	 # 
	 # @param tokenString String representation of the token to be created.
	 # @return The token representation of the input data.
	 # @throws GadgetException If tokenString is not a valid token
	def createToken(self, tokenString):
		from lib import Util;
		Util.abstract();
class JsMinException (Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)
	
class JsMin:
	def __init__(self, inputs):
		self.ORD_LF = 10;
		self.ORD_SPACE = 32;
		self.a = '';
		self.b = '';
		self.inputIndex = 0;
		self.inputLength = 0;
		self.lookAhead = None;
		self.output = '';
		self.inputs = inputs.replace("\r\n", "\n");
		self.inputLength = len(self.inputs);

	#  -- Public Static Methods --------------------------------------------------
	
	@staticmethod
	def minify(js):
		jsmin = JsMin(js);
		return jsmin.min();

	#  -- Protected Instance Methods ---------------------------------------------

	def action(self, d):
		if(d == 1):
			self.output = self.output + self.a;
		elif(d == 2):
			self.a = self.b;
			if (self.a == "'" or self.a == '"'):
				while (True):
					self.output = self.output + self.a;
					self.a = self.get();
					
					if (self.a == self.b):
						break;
					
					if (ord(self.a) <= self.ORD_LF):
						raise JsMinException, 'Unterminated string literal.';
					
					if (self.a == '\\'):
						self.output = self.output + self.a;
						self.a = self.get();
		elif(d == 3):
			self.b = self.next();
			
			if (self.b == '/' and (self.a == '(' or self.a == ',' or self.a == '=' or self.a == ':' or self.a == '[' or self.a == '!' or self.a == '&' or self.a == '|' or self.a == '?')):
				
				self.output = self.output + self.a + self.b;
				
				while(True):
					self.a = self.get();
					
					if (self.a == '/'):
						break;
					elif (self.a == '\\'):
						self.output = self.output + self.a;
						self.a = self.get();
					elif (ord(self.a) <= self.ORD_LF):
						raise JsMinException, 'Unterminated regular expression literal.';
					
					self.output = self.output + self.a;
				
				self.b = self.next();

	def get(self):
		c = self.lookAhead;
		self.lookAhead = None;
		
		if (c == None):
			if (self.inputIndex < self.inputLength):
				c = self.inputs[self.inputIndex];
				self.inputIndex = self.inputIndex + 1;
			else:
				c = None;
		
		if (c == "\r"):
			return "\n";

		if (c == None or c == "\n" or ord(c) >= self.ORD_SPACE):
			return c;
		
		return ' ';

	def isAlphaNum(self, c):
		import re;
		matches = re.compile('^[\w\]').findall(c);
		output = (ord(c) > 126 or c == '\\' or matches == []);
		return output;

	def __strip_(self):
		import re;
		from lib import Logger;
		
		#Logger.quickLog("JsMin.minify - stripping the comments", Logger.DEBUG);

		# [TODO]: remove all js comments starteg '//' but check for urls http:// :)

		#regex = re.compile('[\n]{1,}[\/]{2}[^\n]*');
		#regex = re.compile('[\/]{2}[^\n]*');
		#data = regex.sub('', self.inputs);

		data = self.inputs;

		regex = re.compile(r"/\*.*?\*/", re.MULTILINE|re.DOTALL);
		data = regex.sub("", data);

		self.output = data;

		return self.output;

	def min(self):
		
		#return self.inputs;
		return self.__strip_();
		# changed to only remove the comments
		self.a = "\n";
		self.action(3);
		
		while (self.a != None):
			if(self.a == ' '):
				if (self.isAlphaNum(self.b)):
					self.action(1);
				else:
					self.action(2);
			elif(self.a == '\n'):
				if(self.b == '{' or self.b == '[' or self.b == '(' or self.b == '+' or self.b == '-'):
					self.action(1);
				elif(self.b == ' '):
					self.action(3);
				else:
					if (self.b != None and self.isAlphaNum(self.b)):
						self.action(1);
					else:
						self.action(2);
			else:
				if(self.b == ' '):
					if (self.isAlphaNum(self.a)):
						self.action(1);
					else:
						self.action(3);
				elif(self.b == '\n'):
					if(self.a == '}' or self.a == ']' or self.a == ')' or self.a == '+' or self.a == '-' or self.a == '"' or self.a == "'"):
						self.action(1);
					else:
						if (self.isAlphaNum(self.a)):
							self.action(1);
						else:
							self.action(3);
				else:
					self.action(1);
		return self.output;

	def next(self):
		c = self.get();
		if (c == '/'):
			peekChar = self.peek();
			if(peekChar == '/'):
				while(True):
					c = self.get();
					if (ord(c) <= self.ORD_LF):
						return c;
					
			elif(peekChar == '*'):
				self.get();
				i = 0;
				while (True):
					g = self.get();
					
					if(g == '*'):
						if (self.peek() == '/'):
							self.get();
							return ' ';
					elif(g == None):
						raise JsMinException, 'Unterminated comment.' + self.output;
						#break;
			else:
				return c;
		return c;

	def peek(self):
		self.lookAhead = self.get();
		return self.lookAhead;



'''
 * An abstract representation of a signing token.
 * Use in conjunction with @code SecurityTokenDecoder.
'''
class SecurityToken:

	@staticmethod
	def createFromToken(token, maxage):
		pass;

	@staticmethod
	def createFromValues(owner, viewer, app, domain, appUrl, moduleId):
		pass;

	'''
	 * is this an anonymous token? Always check this before using the owner/viewer/etc
	 * 
	 * @return boolean if it's anonymous
	'''
	def isAnonymous(self):
		from lib import Util;
		Util.abstract();
		

	'''
	 * Serializes the token into a string. This can be the exact same as
	 * toString; using a different name here is only to force interface
	 * compliance.
	 *
	 * @return A string representation of the token.
	'''
	def toSerialForm(self):
		from lib import Util;
		Util.abstract();


	'''
	 * @return the owner from the token, or null if there is none.
	'''
	def getOwnerId(self):
		from lib import Util;
		Util.abstract();


	'''
	 * @return the viewer from the token, or null if there is none.
	'''
	def getViewerId(self):
		from lib import Util;
		Util.abstract();

	'''
	 * @return the application id from the token, or null if there is none.
	'''
	def getAppId(self):
		from lib import Util;
		Util.abstract();

	'''
	 * @return the domain from the token, or null if there is none.
	'''
	def getDomain(self):
		from lib import Util;
		Util.abstract();


	'''
	 * @return the URL of the application
	'''
	def getAppUrl(self):
		from lib import Util;
		Util.abstract();


	'''
	 * @return the module ID of the application
	'''
	def getModuleId(self):
		from lib import Util;
		Util.abstract();




class UrlGenerator:

	@staticmethod
	def getIframeURL(gadget, context):
		import  urllib;

		inlineJs = '';
		for library in gadget.getJsLibraries():
			type = library.getType();
			if (type != 'URL'):
				inlineJs = inlineJs + library.getContent() + "\n";
			
		
		import md5
		v = md5.new(inlineJs).hexdigest();
		
		view = HttpUtil.getView(gadget, context);
		
		up = '';
		prefs = context.getUserPrefs();
		for pref in gadget.getUserPrefs():
			name = pref.getName();
			value = prefs.getPref(name);
			if (value == None):
				value = pref.getDefaultValue();
			
			up = up + '&up_' + urllib.quote(name) + '=' . urllib.quote(value);
		
		
		# note: put the URL last, else some browsers seem to get confused (reported by hi5)
		mid = '&mid=' + context.getModuleId() if context.getModuleId() != 0 else ''
		vs =  'nocache=1' if context.getIgnoreCache() else '&v=' + v;

		return Config.get('default_iframe_prefix') + 'container=' + context.getContainer() + vs + mid + '&lang=' . context.getLocale().getLanguage() + '&country=' + context.getLocale().getCountry() + '&view=' + view.getName() + up + '&url=' . urllib.quote(context.getUrl());



'''
 * This class impliments memcached based caching It'll generally be more
 * usefull in a multi-server envirionment then the file based caching,
 * (in a single server setup file based caching is actually faster)
'''
class CacheMemcache(Cache):
	
	
	

	def __init__(self):
		from lib import Config;

		if (Config.get('cache_host') == '' or Config.get('cache_port') == ''):
			raise CacheException, "You need to configure a cache server host and port to use the memcache backend";
		
		self.host = Config.get('cache_host');
		self.port = Config.get('cache_port');

		self.__connection = False;

	def __isLocked(self, key):
		self.__check();

		if (memcache.get(key + '.lock') == None):
			return False;
		
		return True;

	def __createLock(self, datakey):
		self.__check();
		# the interesting thing is that this could fail if the lock was created in the meantime..
		# but we'll ignore that out of convenience
		from google.appengine.api import memcache;
		memcache.add(key = datakey + '.lock', value='', time=5);
	

	def __removeLock(self, key):
		self.__check();
		# suppress all warnings, if some other process removed it that's ok too
		from google.appengine.api import memcache;
		memcache.delete(key + '.lock');

	def __waitForLock(self, key):
		self.__check();
		# 20 x 250 = 5 seconds
		tries = 20;
		cnt = 0;
		import time;

		while True:		
			# 250 ms is a long time to sleep, but it does stop the server from burning all resources on polling locks..
			#todo
			tim.sleep(.250);
			cnt = cnt + 1;
			if (cnt >= tries or not self.__isLocked()):
				break;

		if (self.__isLocked()):
			# 5 seconds passed, assume the owning process died off and remove it
			self.__removeLock(key);


	# I prefer lazy initalization since the cache isn't used every request
	# so this potentially saves a lot of overhead
	def __connect(self):
		pass;
		#if ( self.connection = @memcache_pconnect(self.host, self.port)) {
		#	raise CacheException("Couldn't connect to memcache server");
		

	def __check(self):
		if (not self.__connection):
			self.__connect();
		

	def get(self, key, expiration = False):
		self.__check();
		
		from google.appengine.api import memcache;

		if (not expiration):
			from lib import Config;
			# default to global cache time
			expiration = Config.get('cache_time');

		ret = memcache.get(key);

		if (ret == None):
			return False;

		#if (time() - ret['time'] > expiration) {
		#	self.delete(key);
		#	return False;
		
		return ret;

	def set(self, datakey, keyvalue, expiration = False):
		self.__check();
		from google.appengine.api import memcache;

		if (not expiration):
			from lib import Config;
			# default to global cache time
			expiration = Config.get('cache_time');

		# we store it with the cache_time default expiration so objects will atleast get cleaned eventually.
		#if (@memcache_set(self.connection, key, array('time' => time(), 
			#'data' => value), False, Config.Get('cache_time')) == False) {
		memcache.set(key = datakey, value = keyvalue, time = expiration);				
			#raise CacheException, "Couldn't store data in cache";
		

	def delete(self, key):
		self.__check();
		from google.appengine.api import memcache;

		memcache.delete(key);

class BlobCrypter:
	def wrap(self, ina):
	        from lib import Util;
		Util.abstract();
	def unwrap(self, ina, maxAgeSec):
		from lib import Util;
		Util.abstract();

class GeneralSecurityException(Exception):
	def __init__(self, value):
		self.value = value
	def __str__(self):
		return repr(self.value)

class Crypto():
	
	def __init__(self):
		# HMAC algorithm to use
		self.HMAC_TYPE = "HMACSHA1";
	
		# minimum safe length for hmac keys (this is good practice, but not 
		# actually a requirement of the algorithm
		self.__MIN_HMAC_KEY_LEN = 8;
	
		# Encryption algorithm to use
		self.__CIPHER_TYPE = "AES/CBC/PKCS5Padding";
	
		self.__CIPHER_KEY_TYPE = "AES";
	
		# Use keys of this length for encryption operations
		self.CIPHER_KEY_LEN = 16;
	
		self.__CIPHER_BLOCK_SIZE = 16;
	
		# Length of HMAC SHA1 output
		self.HMAC_SHA1_LEN = 20;

	def hmacSha1Verify(self, key, ina, expected):
		hmac = self.hmacSha1(key, ina);
		if (hmac != expected):
			raise GeneralSecurityException("HMAC verification failure");

	def aes128cbcEncrypt(self, key, text):
		# Open the cipher 
		td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
		if (td):
			raise GeneralSecurityException('Invalid mcrypt cipher, check your libmcrypt library and php-mcrypt extention');
		# replaced MCRYPT_DEV_RANDOM with MCRYPT_RAND since windows doesn't have /dev/rand :)
		import time;
		#srand((double)microtime() * 1000000);
		srand(time.time() * 1000000);
		iv = mcrypt_create_iv(mcrypt_enc_get_iv_size(td), MCRYPT_RAND);
		# Intialize encryption
		mcrypt_generic_init(td, key, iv);
		# Encrypt data
		encrypted = mcrypt_generic(td, text);
		# Terminate encryption handler */
		mcrypt_generic_deinit(td);

		 #  AES-128-CBC encryption.  The IV is returned as the first 16 bytes of the cipher text.
		return iv + encrypted;

	def aes128cbcDecrypt(self, key, encrypted_text):
		#  Open the cipher
		td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
		iv = substr(encrypted_text, 0, self.CIPHER_BLOCK_SIZE);
		#  Initialize encryption module for decryption */
		mcrypt_generic_init(td, key, iv);
		#  Decrypt encrypted string */
		encrypted = encrypted_text[0,Crypto.CIPHER_BLOCK_SIZE];
		decrypted = mdecrypt_generic(td, encrypted);
		#  Terminate decryption handle and close module */
		mcrypt_generic_deinit(td);
		mcrypt_module_close(td);
		#  Show string */
		return trim(decrypted);

	def hmacSha1(self, key, data):
		blocksize = 64;
		import sha;
		hashfunc = sha;
		if (len(key) > blocksize):
			key = pack('H*', hashfunc(key));
		key = key.center(blocksize, chr(0x00));
		ipad = '';
		i = 0;
		while i < blocksize:
			ipad = ipad + chr(0x36);
			i = i + 1
		opad = '';
		i = 0;
		while i < blocksize:
			opad = opad + chr(0x5c);
			i = i + 1;
		from lib import Util;
		import struct;
		import sys;		
		hmac_val = struct.pack('s', (sha.new(Util.xor_crypt(key,opad) + struct.pack('s', (sha.new(Util.xor_crypt(key,ipad) + data)).hexdigest())).hexdigest()));
		return hmac_val;
